package com.mrobuy.jdvc.service.impl;

import com.gavel.annotation.FieldMeta;
import com.gavel.database.SQLExecutor;
import com.gavel.utils.StringUtils;
import com.google.gson.Gson;
import com.jd.open.api.sdk.DefaultJdClient;
import com.jd.open.api.sdk.JdClient;
import com.jd.open.api.sdk.request.supplier.VcLibraryGetUploadTokenRequest;
import com.jd.open.api.sdk.response.supplier.VcLibraryGetUploadTokenResponse;
import com.mrobuy.jd.JdClientFactory;
import com.mrobuy.jd.api.Jos;
import com.mrobuy.jdvc.dao.*;
import com.mrobuy.jdvc.entity.JDAccount;
import com.mrobuy.jdvc.entity.VCItem;
import com.mrobuy.jdvc.entity.VCItemPic;
import com.mrobuy.jdvc.entity.VCUpdateToken;
import com.mrobuy.jdvc.model.VCSku;
import com.mrobuy.jdvc.service.ProductImageService;
import com.mrobuy.util.IdentifierGen;
import okhttp3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Service("productImageService")
public class ProductImageServiceImpl implements ProductImageService {

    private static Logger LOG = LoggerFactory.getLogger(ProductImageService.class);

    @Autowired
    private JDAccountDao jdAccountDao;

    @Autowired
    private VCSkuDao vcSkuDao;

    @Autowired
    private VCItemDao vcItemDao;

    @Autowired
    private VCItemPicDao vcItemPicDao;

    @Autowired
    private VCUpdateTokenDao vcUpdateTokenDao;


    private static long TIMESTAMP = 0;

    //  token 有效期: 8分钟
    private static long EXPRIE = 8*60*1000;

    private static String UPLOAD_URL = "";

    private static Map<String, VCUpdateToken> UPLOAD_URL_MAP = new ConcurrentHashMap<>();

    @Override
    public List<VCSku> loadSku(String wareId) {
        return vcSkuDao.load(wareId);
    }

    @Override
    public void upload(String skuid, String type, MultipartFile file) {

        if (file.isEmpty()) {
            return;
        }

        BufferedOutputStream stream = null;

        File dest = new File(file.getOriginalFilename());
        System.out.println("File: " + dest.getAbsolutePath());
        try {
            byte[] bytes = file.getBytes();
            stream = new BufferedOutputStream(new FileOutputStream(dest));
            stream.write(bytes);
            stream.close();

            JdClient client = JdClientFactory.jdClient("FEAFBABCDEEC48A569A10818138D7841");

            String uploadUrl = getUploadUrl(client);

            System.out.println("URL: " + uploadUrl);

            ResponseBody responseBody = upload_p(uploadUrl, dest.getAbsolutePath(), dest.getName());

            String text = responseBody.string();

            System.out.println("图片上传: " + text);

            Result result =  new Gson().fromJson(text, Result.class);

            if ( result.getCode()!=null && result.getCode()==1000 ) {
                VCUpdateToken updateToken = vcUpdateTokenDao.load();
                vcUpdateTokenDao.delete(updateToken);
            }

            VCItem vcItem = vcItemDao.loadBySkuId(skuid);

            VCItemPic itemPic = new VCItemPic();
            itemPic.setId(IdentifierGen.uuid());
            itemPic.setWareId(vcItem.getWareId());
            itemPic.setSkuName(vcItem.getSkuName());
            itemPic.setSkuId(skuid);
            itemPic.setType(type);

            String orgUrl = result.getMsg();
            try {
                itemPic.setUrl(orgUrl.split("vc/")[1]);
            } catch (Exception e) {
                itemPic.setUrl(orgUrl);
            }


            vcItemPicDao.insert(itemPic);

//            @FieldMeta(name = "WAREID", title = "商品ID", length = 20)
//            private String wareId;
//
//
//            @FieldMeta(name = "SKUNAME", title = "商品名称", length = 100)
//            private String skuName;
//
//
//            @FieldMeta(name = "ISPRIMARY", title = "是否主图")
//            private Integer isprimary;
//
//            @FieldMeta(name = "POS", title = "图片位置")
//            private Integer pos;


        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if ( stream!=null ) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    @Override
    public void picdelete(String id) {
        VCItemPic itemPic = vcItemPicDao.loadById(id);
        if ( itemPic!=null ) {
            vcItemPicDao.delete(itemPic);
        }
    }

    private String getUploadUrl(String vendor) {

        if ( StringUtils.isBlank(vendor) ) {
            return null;
        }

        if ( UPLOAD_URL_MAP.containsKey(vendor.trim()) ) {
            VCUpdateToken updateToken =  UPLOAD_URL_MAP.get(vendor.trim());
            if ( updateToken.getStartTime() - System.currentTimeMillis() < EXPRIE ) {
                if ( StringUtils.isNotBlank(updateToken.getUploadUrl()) ) {
                    return updateToken.getUploadUrl();
                }
            }

            vcUpdateTokenDao.delete(updateToken);
        }


        VCUpdateToken updateToken = vcUpdateTokenDao.load(vendor);
        if ( updateToken!=null ) {
            if ( updateToken.getStartTime() - System.currentTimeMillis() < EXPRIE ) {
                if ( StringUtils.isNotBlank(updateToken.getUploadUrl()) ) {
                    UPLOAD_URL_MAP.put(vendor.trim(), updateToken);
                    return updateToken.getUploadUrl();
                }
            }
            vcUpdateTokenDao.delete(updateToken);
        }


        try {
            JDAccount account = jdAccountDao.loadByVendor(vendor);
            JdClient jdClient = new DefaultJdClient(Jos.SERVER, account.getAccess_token(),  account.getAppkey(), account.getAppsecret());

            VcLibraryGetUploadTokenRequest request=new VcLibraryGetUploadTokenRequest();
            VcLibraryGetUploadTokenResponse response = jdClient.execute(request);

            if ( response!=null && response.getUpdateToken()!=null ) {
                updateToken = new VCUpdateToken(response.getUpdateToken().getUploadUrl(), System.currentTimeMillis(), vendor);
                vcUpdateTokenDao.insert(updateToken);
                UPLOAD_URL_MAP.put(vendor.trim(), updateToken);
                return updateToken.getUploadUrl();
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOG.error(e.getMessage(), e.getCause());
        }

        return null;
    }


    private String getUploadUrl(JdClient client) throws Exception {

        if ( TIMESTAMP - System.currentTimeMillis() < EXPRIE ) {
            if ( StringUtils.isNotBlank(UPLOAD_URL) ) {
                return UPLOAD_URL;
            }
        }

        UPLOAD_URL = "";

        VCUpdateToken updateToken = vcUpdateTokenDao.load();
        if ( updateToken!=null ) {
            if ( updateToken.getStartTime() - System.currentTimeMillis() < EXPRIE ) {
                if ( StringUtils.isNotBlank(updateToken.getUploadUrl()) ) {
                    TIMESTAMP = updateToken.getStartTime();
                    UPLOAD_URL = updateToken.getUploadUrl();
                    return UPLOAD_URL;
                }
            }
            vcUpdateTokenDao.delete(updateToken);
        }


        VcLibraryGetUploadTokenRequest request=new VcLibraryGetUploadTokenRequest();
        VcLibraryGetUploadTokenResponse response = client.execute(request);

        if ( response!=null && response.getUpdateToken()!=null ) {
            updateToken = new VCUpdateToken(response.getUpdateToken().getUploadUrl(), System.currentTimeMillis());
            vcUpdateTokenDao.insert(updateToken);
            TIMESTAMP = updateToken.getStartTime();
            UPLOAD_URL = updateToken.getUploadUrl();
        }

        return UPLOAD_URL;
    }


    public String upload(String vendor, String filePath, String fileName) throws Exception {


        int times = 0;

        while ( true ) {

            String url = getUploadUrl(vendor);

            ResponseBody response = upload_p(url, filePath, fileName);
            Result result =  new Gson().fromJson(response.string(), Result.class);
            if ( !result.isSuccess() ) {
                if ( result.getCode() == 1000 && times < 3 ) {
                    clear(vendor);
                    times++;
                    continue;
                }
                throw new Exception(result.getMsg());
            }
            return result.getMsg();
        }
    }

    private void clear(String vendor) {
        VCUpdateToken updateToken = vcUpdateTokenDao.load(vendor);
        if ( updateToken!=null ) {
            vcUpdateTokenDao.delete(updateToken);
        }
        UPLOAD_URL_MAP.remove(vendor);
    }

    private ResponseBody upload_p(String url, String filePath, String fileName) throws Exception {

        OkHttpClient client = new OkHttpClient();
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("file", fileName, RequestBody.create(MediaType.parse("multipart/form-data"), new File(filePath)))
                .build();

        Request request = new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new Exception("Unexpected code " + response);
        }
        return response.body();
    }

    public class Result {

        /**
         * success : true
         * code : null
         * msg : http://img20.360buyimg.com/vc/jfs/t1/134396/8/14274/54945/5f9d81d2E715dd4d9/632087befc9ade25.jpg
         */

        private boolean success;
        private Integer code;
        private String msg;

        public Result() {
        }

        public Result(boolean success, Integer code, String msg) {
            this.success = success;
            this.code = code;
            this.msg = msg;
        }

        public boolean isSuccess() {
            return success;
        }

        public void setSuccess(boolean success) {
            this.success = success;
        }

        public Integer getCode() {
            return code;
        }

        public void setCode(Integer code) {
            this.code = code;
        }

        public String getMsg() {
            return msg;
        }

        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
}
